home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
176-200
/
disk_195
/
microemacs
/
src.zoo
/
vms.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-03-23
|
33KB
|
1,214 lines
/*
* Advanced VMS terminal driver
*
* Consults the system's terminal tables for both DEC terminals,
* foreign and user defined terminals.
*
* Author: Curtis Smith
* Update history:
* 14-Jul-1987, first revision.
* 02-Jan-1988, by J. A. Lomicka: Code addition for interpreting
* LK201 function keys, application keypad and cursor
* position reports.
* 09-Apr-1988, second revision.
* Major changes:
* 1) H files removed; replaced with globalvalues.
* 2) Terminal now left in ECHO mode. Read call
* disables echo.
* 3) TYPAHD macro now performs correctly.
* 4) $sres variable now accepts NORMAL and WIDE.
* 5) Writes to screen now use QIO without waiting.
* This gives a slight increase in performance.
* Had to make some QIOW a different event flag number.
* 6) Function keys, special keys and arrow keys
* are now bound using the following table:
* FNa-DOWN FNn-5 FN0- FNA-F10 FNN-E1
* FNb-LEFT FNo-6 FN1-F1 FNB-F11 FNO-E2
* FNc-RITE FNp-7 FN2-F2 FNC-F12 FNP-E3
* FNd-UP FNq-8 FN3-F3 FND-F13 FNQ-E4
* FNe-PF1 FNr-9 FN4-F4 FNE-F14 FNR-E5
* FNf-PF2 FNs-. FN5-F5 FNF-F15 FNS-E6
* FNg-PF3 FNt-ENT FN6-F6 FNG-F16 FNT-
* FNh-PF4 FNu-, FN7-F7 FNH-F17 FNU-
* FNi-0 FNv-- FN8-F8 FNI-F18 FNV-
* FNj-1 FNw- FN9-F9 FNJ-F19 FNW-
* FNk-2 FNx- FNK-F20 FNX-
* FNl-3 FNy- FNL- FNY-
* FNm-4 FNz- FNM- FNZ-
* See ebind.h for key bindings.
* 2-dec-88 Curtis Smith
* - These have been rebound to the new machine independant bindings
*/
/** Standard include files **/
#include <stdio.h> /* Standard I/O package */
#include "estruct.h" /* Emacs' structures */
#include "etype.h"
#include "edef.h" /* Emacs' definitions */
#include "elang.h"
#if VMS
/***
* nothing - The nothing function.
*
* This function is used as a placeholder for unimplemented functions,
* or to compile an empty module (which VMS doesn't like).
*
* Nothing returned.
***/
nothing()
{
/* Nothing */
}
#if VMSVT
/** Parameters **/
#define NKEYENT 128 /* Number of keymap entries */
/** VMS's include files **/
#include <descrip.h> /* Descriptor definitions */
/** VMS's global values **/
globalvalue IO$M_NOECHO; /* Suppress echo on read */
globalvalue IO$M_NOFORMAT; /* Suppress formatting on write */
globalvalue IO$M_TIMED; /* Timeout on input */
globalvalue IO$M_TYPEAHDCNT; /* Get typeahead count */
globalvalue IO$_READLBLK; /* Read logical block */
globalvalue IO$_SENSEMODE; /* Sense mode of terminal */
globalvalue IO$_SETMODE; /* Set mode of terminal */
globalvalue IO$_WRITELBLK; /* Write logical block */
globalvalue SMG$K_BEGIN_REVERSE; /* Begin reverse video */
globalvalue SMG$K_COLUMNS; /* Number of columns narrow */
globalvalue SMG$K_END_REVERSE; /* End reverse video */
globalvalue SMG$K_ERASE_TO_END_LINE; /* Erase to end of line */
globalvalue SMG$K_ERASE_WHOLE_DISPLAY; /* Erase entire screen */
globalvalue SMG$K_KEY_0; /* 0 key */
globalvalue SMG$K_KEY_1; /* 1 key */
globalvalue SMG$K_KEY_2; /* 2 key */
globalvalue SMG$K_KEY_3; /* 3 key */
globalvalue SMG$K_KEY_4; /* 4 key */
globalvalue SMG$K_KEY_5; /* 5 key */
globalvalue SMG$K_KEY_6; /* 6 key */
globalvalue SMG$K_KEY_7; /* 7 key */
globalvalue SMG$K_KEY_8; /* 8 key */
globalvalue SMG$K_KEY_9; /* 9 key */
globalvalue SMG$K_KEY_COMMA; /* Comma key */
globalvalue SMG$K_KEY_DOWN_ARROW; /* Down arrow key */
globalvalue SMG$K_KEY_ENTER; /* Enter key */
globalvalue SMG$K_KEY_E1; /* E1 key */
globalvalue SMG$K_KEY_E2; /* E2 key */
globalvalue SMG$K_KEY_E3; /* E3 key */
globalvalue SMG$K_KEY_E4; /* E4 key */
globalvalue SMG$K_KEY_E5; /* E5 key */
globalvalue SMG$K_KEY_E6; /* E6 key */
globalvalue SMG$K_KEY_F1; /* F1 key */
globalvalue SMG$K_KEY_F2; /* F2 key */
globalvalue SMG$K_KEY_F3; /* F3 key */
globalvalue SMG$K_KEY_F4; /* F4 key */
globalvalue SMG$K_KEY_F5; /* F5 key */
globalvalue SMG$K_KEY_F6; /* F6 key */
globalvalue SMG$K_KEY_F7; /* F7 key */
globalvalue SMG$K_KEY_F8; /* F8 key */
globalvalue SMG$K_KEY_F9; /* F9 key */
globalvalue SMG$K_KEY_F10; /* F10 key */
globalvalue SMG$K_KEY_F11; /* F11 key */
globalvalue SMG$K_KEY_F12; /* F12 key */
globalvalue SMG$K_KEY_F13; /* F13 key */
globalvalue SMG$K_KEY_F14; /* F14 key */
globalvalue SMG$K_KEY_F15; /* F15 key */
globalvalue SMG$K_KEY_F16; /* F16 key */
globalvalue SMG$K_KEY_F17; /* F17 key */
globalvalue SMG$K_KEY_F18; /* F18 key */
globalvalue SMG$K_KEY_F19; /* F19 key */
globalvalue SMG$K_KEY_F20; /* F20 key */
globalvalue SMG$K_KEY_LEFT_ARROW; /* Left arrow key */
globalvalue SMG$K_KEY_MINUS; /* Minus key */
globalvalue SMG$K_KEY_PERIOD; /* Period key */
globalvalue SMG$K_KEY_PF1; /* PF1 key */
globalvalue SMG$K_KEY_PF2; /* PF2 key */
globalvalue SMG$K_KEY_PF3; /* PF3 key */
globalvalue SMG$K_KEY_PF4; /* PF4 key */
globalvalue SMG$K_KEY_RIGHT_ARROW; /* Right arrow key */
globalvalue SMG$K_KEY_UP_ARROW; /* Up arrow key */
globalvalue SMG$K_SET_CURSOR_ABS; /* Set cursor */
globalvalue SMG$K_WIDE_SCREEN_COLUMNS; /* Number of columns wide */
globalvalue SMG$K_WIDTH_NARROW; /* Set terminal to narrow mode */
globalvalue SMG$K_WIDTH_WIDE; /* Set terminal to wide mode */
globalvalue SS$_TIMEOUT; /* Status if read timed-out */
globalvalue TT2$M_PASTHRU; /* Passthru mode in t_extend */
/** I/O information block definitions **/
struct iosb { /* I/O status block */
short i_cond; /* Condition value */
short i_xfer; /* Transfer count */
long i_info; /* Device information */
};
struct termchar { /* Terminal characteristics */
char t_class; /* Terminal class */
char t_type; /* Terminal type */
short t_width; /* Terminal width in characters */
long t_mandl; /* Terminal's mode and length */
long t_extend; /* Extended characteristics */
};
struct tahd { /* Typeahead count */
short t_count; /* Number of character waiting */
char t_first; /* Next character available */
char t_resv1; /* Reserved by DEC */
long t_resv2; /* Reserved by DEC */
};
/** Type definitions **/
struct keyent { /* Key mapping entry */
struct keyent * samlvl; /* Character on same level */
struct keyent * nxtlvl; /* Character on next level */
char ch; /* Character */
int code; /* Resulting keycode */
};
/** Command success **/
#define SUCCESS(x) ((x)&1) /* TRUE if successful */
#define FAILURE(x) (((x)&1)==0) /* TRUE if unsuccessful */
/** Values to manage the screen **/
static int termtype; /* Handle to pass to SMG */
static short channel; /* Terminal I/O channel */
static struct termchar oldmode; /* Old terminal modes */
static struct termchar newmode; /* New terminal modes */
static char * begin_reverse; /* Begin reverse video */
static char * end_reverse; /* End reverse video */
static char * erase_to_end_line; /* Erase to end of line */
static char * erase_whole_display; /* Erase whole display */
static char * width_narrow; /* Set narrow size screen */
static char * width_wide; /* Set wide size screen */
static int narrow_char; /* Number of characters narrow */
static int wide_char; /* Number of characters wide */
static char inbuf[64]; /* Input buffer */
static char * inbufh = inbuf; /* Head of input buffer */
static char * inbuft = inbuf; /* Tail of input buffer */
static char outbuf[1024]; /* Output buffer */
static char * outbuft = outbuf; /* Tail of output buffer */
static char keyseq[256]; /* Prefix escape sequence table */
static struct keyent keymap[NKEYENT]; /* Key map */
static struct keyent * nxtkey = keymap; /* Next free key entry */
/** Forward references **/
int vmsopen(), vmsclose(), vmsgetc(), vmsputc(), vmsflush();
int vmsmove(), vmseeol(), vmseeop(), vmsbeep(), vmsrev(), vmscres();
/** Terminal dispatch table **/
TERM term = {
72 - 1, /* Max number of rows allowable */
/* Filled in */ - 1, /* Current number of rows used */
160, /* Max number of columns */
/* Filled in */ 0, /* Current number of columns */
64, /* Min margin for extended lines*/
8, /* Size of scroll region */
100, /* # times thru update to pause */
vmsopen, /* Open terminal at the start */
vmsclose, /* Close terminal at end */
nothing, /* Open keyboard */
nothing, /* Close keyboard */
vmsgetc, /* Get character from keyboard */
vmsputc, /* Put character to display */
vmsflush, /* Flush output buffers */
vmsmove, /* Move cursor, origin 0 */
vmseeol, /* Erase to end of line */
vmseeop, /* Erase to end of page */
vmsbeep, /* Beep */
vmsrev, /* Set reverse video state */
vmscres /* Change screen resolution */
#if COLOR
,
nothing, /* Set forground color */
nothing /* Set background color */
#endif /* COLOR */
};
/***
* vmsmove - Move the cursor (0 origin)
*
* vmsmove calls to the SMG run-time library to produce a character
* sequence to position the cursor. If the sequence cannot be made,
* a string "OOPS" is produced instead, much like the termcap library
* under UNIX. In the case of "OOPS", the user will soon know that
* his terminal entry is incorrect.
*
* Nothing returned.
***/
vmsmove(row, column)
int row; /* Row position */
int column; /* Column position */
{
char buffer[32];
int rlen, status;
static int code = SMG$K_SET_CURSOR_ABS;
static int len = sizeof(buffer);
static int arg[3] = { 2 };
/* SMG assumes the row/column positions are 1 based. */
arg[1] = row + 1;
arg[2] = column + 1;
/* Call to SMG for the sequence */
status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer, arg);
if (SUCCESS(status)) {
buffer[rlen] = '\0';
vmsputs(buffer);
} else
vmsputs("OOPS");
}
/***
* vmscres - Change screen resolution
*
* vmscres changes the screen resolution of the current window.
* Allowable sizes are NORMAL and WIDE.
*
* Nothing returned
***/
vmscres(value)
char * value; /* Value to set */
{
int width;
/* Skip if not supported */
if (width_wide == NULL || width_narrow == NULL)
return;
/* Check value */
if (strcmp(value, "WIDE") == 0) {
width = wide_char;
vmsputs(width_wide);
} else if (strcmp(value, "NORMAL") == 0) {
width = narrow_char;
vmsputs(width_narrow);
}
/* Change width */
oldmode.t_width = newmode.t_width = width;
newwidth(TRUE, width);
/* Set resolution variable */
strcpy(sres, value);
}
/***
* vmsrev - Set the reverse video status
*
* vmsrev either sets or resets the reverse video state, based on the
* boolean argument. This function is only called if the revexist
* boolean variable is set to TRUE. Otherwise there is no reverse
* video available.
*
* Nothing returned.
***/
vmsrev(status)
int status; /* TRUE if setting reverse */
{
vmsputs(status ? begin_reverse : end_reverse);
}
/***
* vmseeol - Erase to end of line
*
* When this function is called, the lines worth of text after the
* cursor is erased. This function is only called if the eolexist
* boolean variable is set to TRUE. Otherwise the display manager
* will produce enough spaces to erase the line.
*
* Nothing returned.
***/
vmseeol()
{
vmsputs(erase_to_end_line);
}
/***
* vmseeop - Erase to end of page (clear screen)
*
* vmseeop really should be called vmsclear because it really should
* be an erase screen function. When called, this routine will send
* the erase entire screen sequence to the output.
*
* Nothing returned.
***/
vmseeop()
{
vmsputs(erase_whole_display);
}
/***
* vmsbeep - Ring the bell
*
* vmsbeep send a bell character to the output. It might be possible
* in the future to include the NOISY definition and attempt to flash
* the screen, perhaps using LIGHT_SCREEN and DARK_SCREEN.
*
* Nothing returned.
***/
vmsbeep()
{
vmsputc('\007');
}
/***
* vmsgetstr - Get an SMG string capability by name
*
* vmsgetstr attempts to obtain the escape sequence for a particular
* job from the SMG library. Most sequences do not require a parameter
* with the sequence, others do. In order to obtain the definition
* without knowing ahead of time whether ornot the definition has a
* parameter, we call SMG once with a parameter and if that fails, we
* try again without one. If both attempts fail, we will return the
* NULL string.
*
* Storage for the sequence comes from a local pool.
*
* Returns: Escape sequence
* NULL No escape sequence available
***/
char * vmsgetstr(code)
int code; /* Request code */
{
char * result;
int rlen, status;
static char seq[1024];
static char * buffer = seq;
static int len = sizeof(seq);
static int arg[2] = { 1, 1 };
/* Get sequence with one parameter */
status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer, arg);
if (FAILURE(status)) {
/* Try again with zero parameters */
status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer);
if (FAILURE(status))
return NULL;
}
/* Check for empty result */
if (rlen == 0)
return NULL;
/* Save current position so we can return it to caller */
result = buffer;
buffer[rlen++] = '\0';
buffer += rlen;
/* Return capability to user */
return result;
}
/***
* vmsgetnum - Get numerical constant from SMG
*
* vmsgetnum attempts to get a numerical constant from the SMG package.
* If the constant cannot be found, -1 is returned.
***/
int vmsgetnum(code)
int code; /* SMG code */
{
int status, result;
/* Call SMG for code translation */
status = SMG$GET_NUMERIC_DATA(&termtype, &code, &result);
return FAILURE(status) ? -1 : result;
}
/***
* vmsaddkey - Add key to key map
*
* vmsaddkey adds a new escape sequence to the sequence table.
* I am not going to try to explain this table to you in detail.
* However, in short, it creates a tree which can easily be transversed
* to see if input is in a sequence which can be translated to a
* function key (arrows and find/select/do etc. are treated like
* function keys). If the sequence is ambiguous or duplicated,
* it is silently ignored.
*
* Nothing returned
***/
vmsaddkey(code, fn)
int code; /* SMG key code */
int fn; /* Resulting keycode */
{
char * seq;
int first;
struct keyent * cur, * nxtcur;
/* Skip on NULL sequence */
seq = vmsgetstr(code);
if (seq == NULL)
return;
/* If no keys defined, go directly to insert mode */
first = 1;
if (nxtkey != keymap) {
/* Start at top of key map */
cur = keymap;
/* Loop until matches exhast */
while (*seq) {
/* Do we match current character */
if (*seq == cur->ch) {
/* Advance to next level */
seq++;
cur = cur->nxtlvl;
first = 0;
} else {
/* Try next character on same level */
nxtcur = cur->samlvl;
/* Stop if no more */
if (nxtcur)
cur = nxtcur;
else
break;
}
}
}
/* Check for room in keymap */
if (strlen(seq) > NKEYENT - (nxtkey - keymap))
return;
/* If first character if sequence is inserted, add to prefix table */
if (first)
keyseq[(unsigned char) *seq] = 1;
/* If characters are left over, insert them into list */
for (first = 1; *seq; first = 0) {
/* Make new entry */
nxtkey->ch = *seq++;
nxtkey->code = fn;
/* If root, nothing to do */
if (nxtkey != keymap) {
/* Set first to samlvl, others to nxtlvl */
if (first)
cur->samlvl = nxtkey;
else
cur->nxtlvl = nxtkey;
}
/* Advance to next key */
cur = nxtkey++;
}
}
/***
* vmscap - Get capabilities from VMS's SMG library
*
* vmscap retrives all the necessary capabilities from the SMG
* library to operate microEmacs. If an insufficent number of
* capabilities are found for the particular terminal, an error
* status is returned.
*
* Returns: 0 if okay, <>0 if error
***/
int vmscap()
{
char * set_cursor_abs;
int status;
/* Start SMG package */
status = SMG$INIT_TERM_TABLE_BY_TYPE(&oldmode.t_type, &termtype);
if (FAILURE(status)) {
printf(TEXT189);
/* "Cannot find entry for terminal type.\n" */
printf(TEXT190);
/* "Check terminal type with \"SHOW TERMINAL\" or\n" */
printf(TEXT191);
/* "try setting with \"SET TERMINAL/INQUIRE\"\n" */
return 1;
}
/* Get reverse video */
begin_reverse = vmsgetstr(SMG$K_BEGIN_REVERSE);
end_reverse = vmsgetstr(SMG$K_END_REVERSE);
revexist = begin_reverse != NULL && end_reverse != NULL;
/* Get erase to end of line */
erase_to_end_line = vmsgetstr(SMG$K_ERASE_TO_END_LINE);
eolexist = erase_to_end_line != NULL;
/* Get more neat stuff */
erase_whole_display = vmsgetstr(SMG$K_ERASE_WHOLE_DISPLAY);
width_wide = vmsgetstr(SMG$K_WIDTH_WIDE);
width_narrow = vmsgetstr(SMG$K_WIDTH_NARROW);
narrow_char = vmsgetnum(SMG$K_COLUMNS);
wide_char = vmsgetnum(SMG$K_WIDE_SCREEN_COLUMNS);
set_cursor_abs = vmsgetstr(SMG$K_SET_CURSOR_ABS);
/* Disable resoultion if unreasonable */
if (narrow_char < 10 || wide_char < 10) {
width_wide = width_narrow = NULL;
strcpy(sres, "NORMAL");
} else
/* Kludge resolution */
strcpy(sres, oldmode.t_width == wide_char ? "WIDE" : "NORMAL");
/* Check for minimal operations */
if (set_cursor_abs == NULL || erase_whole_display == NULL) {
printf(TEXT192);
/* "The terminal type does not have enough power to run\n" */
printf(TEXT193);
/* "MicroEMACS. Try a different terminal or check\n" */
printf(TEXT194);
/* "type with \"SHOW TERMINAL\".\n" */
return 1;
}
/* Add function keys to keymapping table */
vmsaddkey(SMG$K_KEY_DOWN_ARROW, 'N');
vmsaddkey(SMG$K_KEY_LEFT_ARROW, 'B');
vmsaddkey(SMG$K_KEY_RIGHT_ARROW, 'F');
vmsaddkey(SMG$K_KEY_UP_ARROW, 'P');
vmsaddkey(SMG$K_KEY_PF1, '1');
vmsaddkey(SMG$K_KEY_PF2, '2');
vmsaddkey(SMG$K_KEY_PF3, '3');
vmsaddkey(SMG$K_KEY_PF4, '4');
vmsaddkey(SMG$K_KEY_0, ALTD | '0');
vmsaddkey(SMG$K_KEY_1, ALTD | '1');
vmsaddkey(SMG$K_KEY_2, ALTD | '2');
vmsaddkey(SMG$K_KEY_3, ALTD | '3');
vmsaddkey(SMG$K_KEY_4, ALTD | '4');
vmsaddkey(SMG$K_KEY_5, ALTD | '5');
vmsaddkey(SMG$K_KEY_6, ALTD | '6');
vmsaddkey(SMG$K_KEY_7, ALTD | '7');
vmsaddkey(SMG$K_KEY_8, ALTD | '8');
vmsaddkey(SMG$K_KEY_9, ALTD | '9');
vmsaddkey(SMG$K_KEY_PERIOD, SHFT|'.');
vmsaddkey(SMG$K_KEY_ENTER, SHFT|CTRL|'M');
vmsaddkey(SMG$K_KEY_COMMA, SHFT|',');
vmsaddkey(SMG$K_KEY_MINUS, SHFT|'-');
vmsaddkey(SMG$K_KEY_F1, '1');
vmsaddkey(SMG$K_KEY_F2, '2');
vmsaddkey(SMG$K_KEY_F3, '3');
vmsaddkey(SMG$K_KEY_F4, '4');
vmsaddkey(SMG$K_KEY_F5, '5');
vmsaddkey(SMG$K_KEY_F6, '6');
vmsaddkey(SMG$K_KEY_F7, '7');
vmsaddkey(SMG$K_KEY_F8, '8');
vmsaddkey(SMG$K_KEY_F9, '9');
vmsaddkey(SMG$K_KEY_F10, '0');
vmsaddkey(SMG$K_KEY_F11, SHFT | '1');
vmsaddkey(SMG$K_KEY_F12, SHFT | '2');
vmsaddkey(SMG$K_KEY_F13, SHFT | '3');
vmsaddkey(SMG$K_KEY_F14, SHFT | '4');
vmsaddkey(SMG$K_KEY_F15, SHFT | '5');
vmsaddkey(SMG$K_KEY_F16, SHFT | '6');
vmsaddkey(SMG$K_KEY_F17, SHFT | '7');
vmsaddkey(SMG$K_KEY_F18, SHFT | '8');
vmsaddkey(SMG$K_KEY_F19, SHFT | '9');
vmsaddkey(SMG$K_KEY_F20, SHFT | '0');
vmsaddkey(SMG$K_KEY_E1, CTRL | 'S');
vmsaddkey(SMG$K_KEY_E2, 'C');
vmsaddkey(SMG$K_KEY_E3, 'D');
vmsaddkey(SMG$K_KEY_E4, ALTD | 'S');
vmsaddkey(SMG$K_KEY_E5, 'Z');
vmsaddkey(SMG$K_KEY_E6, 'V');
/* Everything okay */
return 0;
}
/***
* vmsgtty - Get terminal type from system control block
*
* vmsgtty obtains the terminal's information such as flags modes,
* baud rate, size etc. and stores it in the structure block.
* If the block cannot be obtainedm, an error condition is returned.
*
* Returns: Status
***/
int vmsgtty(tc)
struct termchar * tc; /* Terminal characteristics */
{
int status;
struct iosb io;
/* Get terminal characteristics */
status = SYS$QIOW(1, channel, IO$_SENSEMODE, &io, 0, 0,
tc, sizeof(*tc), 0, 0, 0, 0);
/* Check status */
return FAILURE(status) && FAILURE(io.i_cond);
}
/***
* vmsstty - Set terminal control block
*
* vmsstty takes a previous vmsgtty with modifications, and stores
* this as the current terminal control block.
*
* Returns: Status
***/
int vmsstty(tc)
struct termchar * tc; /* Terminal characteristics */
{
int status;
struct iosb io;
/* Set terminal characteristics */
status = SYS$QIOW(1, channel, IO$_SETMODE, &io, 0, 0,
tc, sizeof(*tc), 0, 0, 0, 0);
/* Check status */
return FAILURE(status) && FAILURE(io.i_cond);
}
/***
* vmsclose - Close the connection to the terminal
*
* vmsclose resets the terminal to the original state and cuts the
* connection. No further operations should be done after closing.
*
* Nothing returned.
***/
vmsclose()
{
/* Flush pending output */
vmsflush();
/* Do this stupid thing for synchronization */
SYS$QIOW(1, channel, IO$_WRITELBLK | IO$M_NOFORMAT,
0, 0, 0, " \b", 2, 0, 0, 0, 0);
/* Reset terminal to original modes */
vmsstty(&oldmode);
/* Release channel */
SYS$DASSGN(channel);
}
/***
* vmsopen - Get terminal type and open terminal
*
* Nothing returned
***/
vmsopen()
{
$DESCRIPTOR(name, "TT");
int status;
/* Open channel to terminal */
status = SYS$ASSIGN(&name, &channel, 0, 0);
if (FAILURE(status)) {
printf(TEXT195);
/* "Cannot open channel to terminal.\n" */
exit(1);
}
/* Get terminal type */
if (vmsgtty(&oldmode)) {
printf(TEXT196);
/* "Cannot obtain terminal settings.\n" */
goto error;
}
/* Get SMG */
if (vmscap())
goto error;
/* Set sizes */
term.t_nrow = ((unsigned int) oldmode.t_mandl >> 24) - 1;
term.t_ncol = oldmode.t_width;
/* Set new terminal modes */
newmode = oldmode;
newmode.t_extend |= TT2$M_PASTHRU;
if (vmsstty(&newmode)) {
printf(TEXT197);
/* "Cannot modify terminal settings.\n" */
goto error;
}
/* Finished! */
return;
/* Make sure terminal deassigned */
error:
/* Release channel */
SYS$DASSGN(channel);
exit(1);
}
/***
* vmsflush - Flush output buffer
*
* vmsflush causes all queued output characters to be written to the
* terminal's screen. We will use SYS$QIO because we don't need to
* wait and because it dramaticly increases performance.
*
* Nothing returned.
***/
vmsflush()
{
int len;
/* Compute size of request */
len = outbuft - outbuf;
/* Skip if zero */
if (len) {
SYS$QIO(0, channel, IO$_WRITELBLK | IO$M_NOFORMAT,
0, 0, 0, outbuf, len, 0, 0, 0, 0);
/* Reset buffer positions */
outbuft = outbuf;
}
}
/***
* vmsputc - Send a character to the screen
*
* vmsputc queues character into a buffer for screen output. When the
* buffer is full the flush routine is called. This is help speed
* things up by avoiding millions of system calls.
*
* Nothing returned.
***/
vmsputc(ch)
char ch; /* Character to add */
{
/* Check for overflow */
if (outbuft == &outbuf[sizeof(outbuf)])
vmsflush();
/* Add character to buffer */
*outbuft++ = ch;
}
/***
* vmsputs - Send a string to vmsputc
*
* vmsputs is a short-cut routine to handle sending a string of characters
* to the character output routine. A check is made for a NULL string,
* while is considered valid. A NULL string will produce no output.
*
* Nothing returned.
***/
vmsputs(string)
char * string; /* String to write */
{
if (string)
while (*string)
vmsputc(*string++);
}
/***
* vmsgchar - Get character directly from VMS
*
* vmsgchar is the lowest level of retrieving character from VMS.
* The argument timed specifies where to wait for a character for
* a short period (1 > wait >= 2 seconds) or indefinately. The short
* period version is used when obtaining a escape sequence.
*
* Returns: character or 0 if no character is available.
***/
char vmsgchar(timed)
int timed; /* TRUE if being timed */
{
char ch;
int status, op;
struct iosb io;
/* Make operation */
op = (timed ? IO$M_TIMED : 0) | IO$_READLBLK | IO$M_NOECHO;
/* Get next character */
status = SYS$QIOW(1, channel, op, &io, 0, 0, &ch, 1, 2, 0, 0, 0);
/* Fatal error */
if (FAILURE(status) || FAILURE(io.i_cond)) {
/* Check for time-out */
if (io.i_cond == SS$_TIMEOUT)
return 0;
/* Real I/O error occured */
printf(TEXT198, status, io.i_cond);
/* "I/O error (%d,%d)\n" */
SYS$DASSGN(channel);
exit(1);
}
/* Return next character */
return ch;
}
/***
* vmsqin - Queue character for input
*
* vmsqin queues the character into the input buffer for later
* reading. This routine will mostly be used by mouse support
* and other escape sequence processing.
*
* Nothing returned.
***/
vmsqin(ch)
char ch; /* Character to add */
{
/* Check for overflow */
if (inbuft == &inbuf[sizeof(inbuf)]) {
/* Annoy user */
vmsbeep();
return;
}
/* Add character */
*inbuft++ = ch;
}
/***
* vmsgcook - Get characters from input device
*
* vmsgcook "cooks" input from the input device and places them into
* the input queue.
*
* Nothing returned.
***/
vmsgcook()
{
char ch;
struct keyent * cur;
/* Get first character untimed */
ch = vmsgchar(0);
vmsqin(ch);
/* Skip if the key isn't a special leading escape sequence */
if (keyseq[(unsigned char) ch] == 0)
return;
/* Start translating */
cur = keymap;
while (cur) {
if (cur->ch == ch) {
/* Is this the end */
if (cur->nxtlvl == NULL) {
/* Replace all character with new sequence */
inbuft = inbuf;
vmsqin(0);
vmsqin(cur->code);
return;
} else {
/* Advance to next level */
cur = cur->nxtlvl;
/* Get next character, timed */
ch = vmsgchar(1);
if (ch == '\0')
return;
/* Queue character */
vmsqin(ch);
}
} else
/* Try next character on same level */
cur = cur->samlvl;
}
}
/***
* vmsgetc - Get a character
*
* vmsgetc obtains input from the character input queue. If the queue
* is empty, a call to vmsgcook() is called to fill the input queue.
*
* Returns: character
***/
int vmsgetc()
{
char ch;
/* Loop until character found */
while (1) {
/* Get input from buffer, if available */
if (inbufh != inbuft) {
ch = *inbufh++;
if (inbufh == inbuft)
inbufh = inbuft = inbuf;
break;
} else
/* Fill input buffer */
vmsgcook();
}
/* Return next character */
return (int) ch;
}
#if FLABEL
/***
* fnclabel - Label function keys
*
* Currently, VMS does not have function key labeling.
*
* Returns: status.
***/
int fnclabel(flag, n)
int flag; /* TRUE if default */
int num; /* Numerical argument */
{
/* On machines with no function keys...don't bother */
return TRUE;
}
#endif /* FLABEL */
/***
* spal - Set palette type
*
* spal sets the palette colors for the 8 colors available. Currently,
* there is nothing here, but some DEC terminals, (VT240 and VT340) have
* a color palette which is available under the graphics modes.
* Further, a foreign terminal could also change color registers.
*
* Nothing returned
***/
spal()
{
/* Nothing */
}
#endif /* VMSVT */
#if TYPEAH
/***
* typahead - Check for pending input
*
* typahead check the input buffer for pending input. If input exists
* TRUE is returned. This routine is used mostly by the display
* update routine to avoid redrawing the entire display when it
* doesn't need to do so.
*
* Returns: boolean.
***/
int typahead()
{
int status;
struct iosb io;
struct tahd tbuf;
/* Check for buffered characters */
if (inbufh != inbuft)
return TRUE;
/* Call to system for character count */
status = SYS$QIOW(1, channel, IO$_SENSEMODE | IO$M_TYPEAHDCNT,
&io, 0, 0, &tbuf, sizeof(tbuf), 0, 0, 0, 0);
if (FAILURE(status) || FAILURE(io.i_cond))
return FALSE;
return tbuf.t_count;
}
#endif /* TYPEAH */
/***
* vmsdcl - Execute or invoke a DCL
*
* vmsdcl without an argument will invoke a new DCL as a new process
* and attach to it. When the DCL returns, emacs will regain control.
* With an argument, the DCL starts and begins executing the command
* line.
*
* Returns: status.
***/
int vmsdcl(command)
char * command; /* Command to execute */
{
int result, status;
struct dsc$descriptor desc, * dp;
/* Set up descriptor */
if (command) {
desc.dsc$a_pointer = command;
desc.dsc$w_length = strlen(command);
desc.dsc$b_dtype = DSC$K_DTYPE_T;
desc.dsc$b_class = DSC$K_CLASS_S;
dp = &desc;
} else
dp = NULL;
/* Turn off raw input */
vmsstty(&oldmode);
/* Call DCL */
status = LIB$SPAWN(dp, 0, 0, 0, 0, 0, &result, 0, 0, 0);
/* Return to raw input */
vmsstty(&newmode);
/* Return status */
return SUCCESS(status) && SUCCESS(result);
}
/***
* spawncli - Spawn a new DCL
*
* spawncli reliquishes control of the terminal and passes it on to
* a newly created DCL process. When the DCL process finishes, the
* screen is redrawen and emacs regains control.
*
* Returns: status
***/
int spawncli(flag, num)
int flag; /* TRUE if default */
int num; /* Numerical argument */
{
/* Restrict usage */
if (restflag)
return resterr();
/* Move to last line and announce */
vmsmove(term.t_nrow, 0);
vmsputs(TEXT199);
/* "[Starting DCL]\r\n" */
vmsflush();
/* Redraw screen on return */
sgarbf = TRUE;
/* Start command */
return vmsdcl(NULL);
}
/***
* spawn - Spawn a command
*
* spawncli reliquishes control of the terminal and passes it on to
* a newly created DCL process. When the DCL process finishes, the
* screen is redrawen and emacs regains control.
*
* Returns: status
***/
int spawn(flag, num)
int flag; /* TRUE if default */
int num; /* Numerical argument */
{
char line[NLINE];
int status;
/* Restrict usage */
if (restflag)
return resterr();
/* Ask for command */
status = mlreply("!", line, sizeof(line));
if (status != TRUE)
return status;
/* Move to last line and announce */
vmsmove(term.t_nrow, 0);
vmsputs(TEXT200);
/* "[Calling DCL]\r\n" */
vmsflush();
/* Run command */
status = vmsdcl(line);
/* Wait for conformation */
vmsputs(TEXT6);
/* "\r\n\n[END]" */
vmsflush();
vmsgchar();
/* Redraw screen on return */
sgarbf = TRUE;
return status;
}
/***
* execprg - Execute a program without using command interpretter
*
* execprg is the same as spawn because there is no reasonable way
* of avoiding the command interpretter. This routine is mostly for
* smaller systems.
*
* Returns: status
***/
int execprg(flag, num)
int flag; /* TRUE if default */
int num; /* Numerical argument */
{
return spawn(flag, num);
}
/***
* pipecmd - Pipe a one line command into a window
*
* pipecmd take a single command and places output into a buffer.
* This is accomplished on non-UNIX machines by sending the result
* of the command interpretter into a temporary file, then reading
* the file into the buffer.
*
* This command is not implemented current, but could be implemented
* and will be once I get some manuals.
*
* Returns: status
***/
int pipecmd(flag, num)
int flag; /* TRUE if default */
int num; /* Numerical argument */
{
mlwrite(TEXT201);
/* "[Not available yet under VMS]" */
return FALSE;
}
/***
* filter - Filter buffer through an external command
*
* filter take a buffer and pipes into a program. This is accomplished
* under non-UNIX systems by writing the buffer to a temporary file
* and running the command with the temporary file as input and another
* temporary file as output. Once the command completes, the buffer
* is replaced by the contents of the second temporary file and
* all temporary files are removed.
*
* This command is currently not implemented, but can be implemented
* and will be once I get the manuals.
*
* Returns: status.
***/
int filter(flag, num)
int flag; /* TRUE if default */
int num; /* Numerical argument */
{
mlwrite(TEXT201);
/* "[Not available yet under VMS]" */
return FALSE;
}
/* return a system dependant string with the current time */
char *PASCAL NEAR timeset()
{
register char *sp; /* temp string pointer */
char buf[16]; /* time data buffer */
extern char *ctime();
time(buf);
sp = ctime(buf);
sp[strlen(sp)-1] = 0;
return(sp);
}
#else
vmshello()
{
}
#endif